package com.leyou.search.serivce.impl;

import com.leyou.common.exception.LyException;
import com.leyou.item.client.ItemClient;
import com.leyou.search.dto.SearchParamDTO;
import com.leyou.search.entity.Goods;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.serivce.SearchService;
import com.leyou.starter.elastic.entity.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.Nested;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private GoodsRepository repository;

    @Autowired
    private ItemClient itemClient;

    @Override
    public Mono<List<String>> suggestName(String key) {

        return this.repository.suggestBySingleField("suggestion", key);
    }

    @Override
    public Mono<PageInfo<Goods>> loadData(SearchParamDTO searchParamDTO) {

        String key = searchParamDTO.getKey();

        if (StringUtils.isBlank(key)) {
            throw new LyException(400, "查询参数条件不能为空");
        }

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //查询条件
        sourceBuilder.query(QueryBuilders.matchQuery("title", searchParamDTO.getKey()));

        //高亮条件
        sourceBuilder.highlighter(new HighlightBuilder().field("title").preTags("<am>").postTags("</am>"));

        //排序条件
        String sortBy = searchParamDTO.getSortBy();

        if (StringUtils.isNotBlank(sortBy)) {
            //添加排序条件，排序字段是动态的，排序方式也是动态的
            sourceBuilder.sort(SortBuilders.fieldSort(sortBy).order(searchParamDTO.getDesc() ? SortOrder.DESC : SortOrder.ASC));
        }

        //添加分页条件
        int size = searchParamDTO.getSize();

        int page = searchParamDTO.getPage();

        sourceBuilder.from((page - 1) * size);

        sourceBuilder.size(size);


        //执行查询
        Mono<PageInfo<Goods>> pageInfoMono = repository.queryBySourceBuilderForPageHighlight(sourceBuilder);

        return pageInfoMono;
    }

    @Override
    public Mono<Map<String, List<?>>> loadFilter(SearchParamDTO searchParamDTO) {



        String key = searchParamDTO.getKey();

        if (StringUtils.isBlank(key)) {
            throw new LyException(400, "查询参数条件不能为空");
        }

        //5大
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //查询条件
        sourceBuilder.query(QueryBuilders.matchQuery("title", searchParamDTO.getKey()));

        sourceBuilder.aggregation(AggregationBuilders.terms("brandAgg").field("brandId"));
        sourceBuilder.aggregation(AggregationBuilders.terms("categoryAggs").field("categoryId"));

        sourceBuilder.aggregation(
                AggregationBuilders.nested("specAgg","specs")
        .subAggregation(AggregationBuilders.terms("nameAgg").field("specs.name")
        .subAggregation(AggregationBuilders.terms("valueAgg").field("specs.value"))));

        //聚合处理
        Mono<Aggregations> aggregationsMono = this.repository.aggregationBySourceBuilder(sourceBuilder);

        //Mono<Aggregations> ===>Mono<Map<String,List<?>>>

        //根据聚合名称获取聚合结果
        return aggregationsMono.map(aggregations -> {

            //查询聚合返回结果
            Map<String,List<?>> result = new HashMap<>();

            Terms brandAgg = aggregations.get("brandAgg");

            List<Long> brandIds = brandAgg.getBuckets()
                    .stream()
                    .map(Terms.Bucket::getKeyAsNumber)
                    .map(Number::longValue)
                    .collect(Collectors.toList());



            result.put("品牌", this.itemClient.queryBrandByIds(brandIds));

            Terms categoryAggs = aggregations.get("categoryAggs");


            List<Long> categoryIds = categoryAggs.getBuckets()
                    .stream()
                    .map(Terms.Bucket::getKeyAsNumber)
                    .map(Number::longValue)
                    .collect(Collectors.toList());

            result.put("分类", this.itemClient.queryCategoryByIds(categoryIds));

            //根据聚合名称获取到规格参数的聚合
            Nested specAgg = aggregations.get("specAgg");

            //从规格参数聚合中获取到 子聚合 名称聚合
            Terms nameAgg = specAgg.getAggregations().get("nameAgg");

            //从名称聚合中获取聚合结果值，从第二层聚合结果中解析获取到第3层聚合
            for (Terms.Bucket bucket : nameAgg.getBuckets()) {
                //获取name部分的聚合的参数key
                String name = bucket.getKeyAsString();

                //获取子聚合
                Terms valueAgg = bucket.getAggregations().get("valueAgg");

                //从子聚合中获取聚合结果
                result.put(name, valueAgg.getBuckets().stream().map(Terms.Bucket::getKeyAsString)
                        .collect(Collectors.toList()));
            }

            return result;
        });
    }
}
